package com.scratch.common.service.db;


import com.scratch.common.redis.constant.RedisConstants;
import com.scratch.common.redis.service.RedisService;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * Created by bpf on 2021/01/20.
 */
@Slf4j
public class DbService extends DbDao {

    private DataSource dataSource;
    private RedisService redisService;

    public DbService(DataSource dataSource, RedisService redisService) {
        super.dataSource = dataSource;
        this.redisService = redisService;
    }

    public void init(Class clazz, DbTable dbTable, DbTypeEnum dbTypeEnum) {
        StopWatch watch = StopWatch.createStarted();
        Boolean redisLock = null;
        try {
            redisLock = redisService.acquireLock(RedisConstants.BaseKey.DB_LOCK.getCode() + dbTable.name(), dbTable.lockTime());
            Optional<List<String>> optionalWifiUserEntityList = Optional.ofNullable(redisLock)
                    .filter(x -> !Objects.isNull(x) && x).map(x -> {
                        return Optional
                                .ofNullable(redisService.llen(RedisConstants.BaseKey.DB_LIST.getCode() + dbTable.name()))
                                .filter(y -> !Objects.isNull(y) && y > 0)
                                .map(y -> y > dbTable.maxLimit() ?
                                        redisService.lrange(RedisConstants.BaseKey.DB_LIST.getCode() + dbTable.name(), 0L, dbTable.maxLimit() - 1L)
                                        : redisService.lrange(RedisConstants.BaseKey.DB_LIST.getCode() + dbTable.name(), 0L, y - 1)
                                ).orElse(null);
                    });
            optionalWifiUserEntityList
                    .filter(x -> !Objects.isNull(x) && x.size() > 0).map(x -> {
                        Map<String, List<String>> map = DbUtils.getTableColumn(dbTypeEnum, clazz);
                        Integer result = null;
                        switch (dbTypeEnum) {
                            case INSERT:
                                result = insert(clazz, x, map.get(DbUtils.KEY_LIST_COLUMN), map.get(DbUtils.KEY_LIST_ATTRIBUTE));
                                break;
                            case UPDATE:
                                result = update(clazz, x, map.get(DbUtils.KEY_LIST_ATTRIBUTE));
                                break;
                            default:
                                break;
                        }
                        return result;
                    }).filter(x -> !Objects.isNull(x) && x > 0).ifPresent(x -> {
                        redisService.ltrim(RedisConstants.BaseKey.DB_LIST.getCode() + dbTable.name(), Long.valueOf(x), -1L);
                        watch.stop();
                        log.info("{}{}表{}条数据耗时{}ms", dbTypeEnum.getDesc(), dbTable.name(), optionalWifiUserEntityList.get().size(), watch.getTime(TimeUnit.MILLISECONDS));
                    });

        } finally {
            redisService.releaseLock(RedisConstants.BaseKey.DB_LOCK.getCode() + dbTable.name());
        }
    }
}
